package skkj;

import java.util.concurrent.Semaphore;

public class MultiThread {

    /**
     * 题解：
     * https://blog.csdn.net/riemann_/article/details/98119372
     */

    /**
     *  1.三个线程循环打印 abc
     *  方法一：两把锁等待
     */

    public static class ThreadPrinter implements Runnable {
        // 至少需要两把锁去保证执行顺序（前后）
        private String name;
        private Object prev;
        private Object self;

        public ThreadPrinter(String name, Object prev, Object self) {
            this.name = name;
            this.prev = prev;
            this.self = self;
        }

        @Override
        public void run() {
            // 这里假设打印十次
            int count = 10;
            while (count > 0) {
                synchronized (prev) {
                    synchronized (self) {
                        System.out.print(name);
                        count --;
                        self.notifyAll();
                    }
                    try {
                        // 这里是为了防止最后一次打印死等
                        if (count != 0) {
                            prev.wait();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }

    public static void main1(String[] args) throws InterruptedException {
        Object a = "a";
        Object b = "b";
        Object c = "c";
        Thread t1 = new Thread(new ThreadPrinter("a", c, a));
        Thread t2 = new Thread(new ThreadPrinter("b", a, b));
        Thread t3 = new Thread(new ThreadPrinter("c", b, c));
        t1.start();
        // 休眠是因为任务执行需要一定时间，这里需要保证锁顺序
        Thread.sleep(10);
        t2.start();
        Thread.sleep(10);
        t3.start();
    }

    /**
     * 方法二：semaphore
     */
    public static class ThreadPrinter2 implements Runnable{
        private String name;
        private Semaphore self;
        private Semaphore next;
        public ThreadPrinter2(String name, Semaphore self, Semaphore next) {
            this.name = name;
            this.self = self;
            this.next = next;
        }


        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    self.acquire();
                    System.out.print(name);
                    next.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        Semaphore a = new Semaphore(1);
        Semaphore b = new Semaphore(0);
        Semaphore c = new Semaphore(0);
        Thread t1 = new Thread(new ThreadPrinter2("a", a, b));
        Thread t2 = new Thread(new ThreadPrinter2("b", b, c));
        Thread t3 = new Thread(new ThreadPrinter2("c", c, a));
        t1.start();
        t2.start();
        t3.start();
    }
}
